Practical Concurrent Haskell by Stefania Loredana Nita & Marius Mihailescu

Practical Concurrent Haskell by Stefania Loredana Nita & Marius Mihailescu

Author:Stefania Loredana Nita & Marius Mihailescu
Language: eng
Format: mobi, epub
Publisher: Apress, Berkeley, CA
Published: 0101-01-01T00:00:00+00:00


initializeBackend connects to an existing communication infrastructure.

findPeers can be evaluated every time we need to get a list of existing nodes that marked their presence through a broadcast.

Master-Slave Configuration

Let’s improve the preceding example by adding a non-operational slave process and a master process that lists its slaves and displays a message for each slave. The first one that needs to be started is a master.

main :: IO ()

main = do

args <- getArgs

case args of

["master", host, port] -> do

backend <- initializeBackend host port initRemoteTable

startMaster backend (master backend)

["slave", host, port] -> do

backend <- initializeBackend host port initRemoteTable

startSlave backend

The following is the code for a master node.

master :: Backend -> [NodeId] -> Process ()

master backend slaves = do

-- Do something interesting with the slaves

liftIO . putStrLn $ "Slaves: " ++ show slaves

-- Terminate the slaves when the master terminates (this is optional)

terminateAllSlaves backend

Obtaining Information About Processes

If we want to obtain information about a certain Cloud Haskell process that is running , we can use the getProcessInfo function, whose ProcessInfo type has the id of the local process and a comprehensive list of the recorded names, monitors, and bindings to process. If the process we want is not running, then the result will be Nothing.

Messages to Processes

Next, we use runProcess, whose arguments are a node and a Process action, and the result will be a Process monad. We need to remark that each process has its own identifier that is utilized for sending messages to processes that are already running. Another important component is the mailbox, where the messages from other processes are stored and organized as a queue in order of arrival.

-- in main

_ <- runProcess node $ do

-- get our own process id

self <- getSelfPid

send self "hello"

hello <- expect :: Process String

liftIO $ putStrLn hello

return ()

Deadlock will not occur in the preceding example when the thread sends and receives messages, because the messages are sent asynchronously. Moreover, if the receiver’s mailbox does not exist, it will not raise an error and the evaluation of send will not obstruct the sender, even if it sends messages to itself. The expect function or the receive* functions could be used by a process to send a message from its mailbox. When a process expects a certain type of message (in this case, it is “selected” via the type annotation "Process String"; in other cases, the type of message might be inferred) and it is not in the mailbox, the process is blocked until it receives the expected message.

Next, we create two processes that are in the same node and make them communicate reciprocally.

import Control.Concurrent (threadDelay)

import Control.Monad (forever)

import Control.Distributed.Process

import Control.Distributed.Process.Node

import Network.Transport.TCP (createTransport, defaultTCPParameters)

replyBack :: (ProcessId, String) -> Process ()

replyBack (sender, msg) = send sender msg

logMessage :: String -> Process ()

logMessage msg = say $ "handling " ++ msg

main :: IO ()

main = do

Right t <- createTransport "127.0.0.1" "10501" defaultTCPParameters

node <- newLocalNode t initRemoteTable

runProcess node $ do

-- Spawn another worker on the local node

echoPid <- spawnLocal $ forever $ do

-- Test our matches in order against each



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.